<script>
addEventListener('WebComponentsReady', function() {

  // given a list of elements, produce a report of rules that
  // match those elements.
  var auditor = {
    
    matchesForDocument: function(elements) {
      var info = [];
      this.documentSheets.forEach(function(sheet) {
        var list = this.matchesForSheet(sheet, elements);
        if (list.length) {
          info.push({sheet: sheet, rules: list});
        }
      }, this);
      return info;
    },

    // TODO(sorvell): support stylesheets inside HTMLImports
    documentSheets: Array.prototype.filter.call(document.styleSheets,
      function(sheet) {
        return !sheet.ownerNode.hasAttribute('scope');
      }
    ),

    matchesForSheet: function(sheet, elements) {
      var info = [];
      Array.prototype.forEach.call(sheet.cssRules, function(rule) {
        var list = this.matchesForRule(rule, elements);
        if (list.length) {
          info.push({selector: rule.selectorText, elements: list});
        }
      }, this);
      return info;
    },

    matchesForRule: function(rule, list) {
      var info = [];
      list.forEach(function(i) {
        var elements = i.elements.filter(function(e) {
          return matchesSelector.call(e, rule.selectorText);
        });
        if (elements.length) {
          info.push({host: i.host, elements: elements});
        }
      });
      return info;
    }

  };

  var p = Element.prototype;
  var matchesSelector = p.matches || p.matchesSelector ||
      p.mozMatchesSelector || p.msMatchesSelector ||
      p.oMatchesSelector || p.webkitMatchesSelector;

  
  // crawl the document and return a list of custom elements with shadyRoots
  // and their scoped contents
  var crawler = {
    // list of elements: array of {host, elements}
    list: function() {
      var list = [];
      var elements = this.elementsWithShadyRoot();
      elements.forEach(function(e) {
        list.push({host: e, elements: this.elementsInsideShadyRoot(e)});
      }, this);
      return list;
    },

    elementsWithShadyRoot: function() {
      var e$ = Polymer.dom(document).querySelectorAll('*');
      return this.filterElementsWithRoots(e$);
    },

    elementsInsideShadyRoot: function(e) {
      var e$ = Polymer.dom(e.root || e).querySelectorAll('*');
      var roots = this.filterElementsWithRoots(e$);
      roots.forEach(function(e) {
        e$ = e$.concat(this.elementsInsideShadyRoot(e));
      }, this);
      return e$;
    },

    filterElementsWithRoots: function(elements) {
      return elements.filter(function(e) {
        return e.shadyRoot;
      });  
    }

  };

  // dump an auditor report
  var logger = {

    dump: function(log) {
      log.forEach(function(l) {
        console.group(l.sheet.ownerNode);
        this.dumpRules(l.rules);
        console.groupEnd(l.sheet.ownerNode);
      }, this);
    },

    dumpRules: function(rules) {
      rules.forEach(function(i) {
        console.group(i.selector);
        console.log(i.elements);
        console.groupEnd(i.selector);
      });
    }

  };
  
  // pruduces a style audit and reports results on the console.
  function audit() {
    var report = auditor.matchesForDocument(crawler.list());
    logger.dump(report);
  }

  audit();

});
</script>
